﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using ca2simulator.shared;
using System.Runtime.Serialization;

namespace ca2simulator.shared.wcf
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    //TODO Add session based communication
    [ServiceContract(CallbackContract=typeof(ISimulationCallback), SessionMode=SessionMode.Required)]
    public interface ICA2SimulationService
    {
        [OperationContract(IsInitiating = true)]
        void Start();

        [OperationContract(IsInitiating=false)]
        bool UploadSimulation(CAContract ca);

        [OperationContract(IsInitiating = false)]
        LatticeContract GetLattice();

        [OperationContract(IsInitiating = false)]
        bool Run();

        [OperationContract(IsInitiating = false)]
        bool Halt();

        [OperationContract(IsInitiating = false)]
        LatticeContract Step(int numStep);

        [OperationContract(IsInitiating = false)]
        bool Subscribe();

        [OperationContract(IsInitiating = false)]
        bool Unsubscribe();

        [OperationContract(IsInitiating = false, IsTerminating = true)]
        bool ReleaseSimulation();
    }

    // Implement callback contracts
    public interface ISimulationCallback
    {
        //TODO Change back to oneway after debug
        [OperationContract]
        void OnLatticeUpdate(LatticeContract updatedLattice);

        [OperationContract]
        void OnLatticeChange(LatticeChangeContract changes);
    }
    
    // This contract is used to send an entire CA with lattice and tranfer function
    [DataContract]
    public class CAContract
    {
        [DataMember]
        public CA2Raw Data {get;set;}
        

        public CAContract(string deltaCode, Lattice initialLattice)
        {
            Data = new CA2Raw(initialLattice, deltaCode);
        }
        public CAContract(CA2Raw rawData)
        {
            Data = rawData;
        }
    }

    // This contract is used to send a lattice
    [DataContract]
    public class LatticeContract
    {
        private Lattice _Lattice;
        [DataMember]
        public Lattice Lattice { get { return _Lattice; } set { _Lattice = value; } }
        public LatticeContract(Lattice lattice)
        {
            _Lattice = lattice;
            //_Lattice = new Lattice(new CellState(), 10, 10);
        }
    }

    [DataContract]
    public class LatticeChangeContract
    {
        [DataMember]
        public CellChange[] Changes { get; set; }
        public LatticeChangeContract(List<CellChange> changes)
        {
            Changes = changes.ToArray();
        }
        public LatticeChangeContract(CellChange[] changes)
        {
            Changes = changes;
        }
    }
}
